package org.budo.launcher.tomcat;

import java.io.InputStream;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.Filter;
import javax.servlet.Servlet;

import org.apache.catalina.Wrapper;
import org.apache.catalina.core.StandardContext;
import org.apache.tomcat.util.descriptor.web.ApplicationParameter;
import org.apache.tomcat.util.descriptor.web.ErrorPage;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import org.budo.launcher.service.config.AbstractWebXmlConfigParser;
import org.budo.launcher.service.config.FilterConf;
import org.budo.launcher.service.config.FilterMappingConf;
import org.budo.launcher.service.config.ServletConf;
import org.budo.xml.Xml;
import org.budo.xml.XmlObject;

/**
 * web.xml 解析程序
 * 
 * @author lmw
 */
public class TomcatWebXmlConfigParser extends AbstractWebXmlConfigParser {
    private StandardContext tomcatContext;

    public TomcatWebXmlConfigParser(InputStream inputStream, StandardContext tomcatContext) {
        XmlObject webXml = Xml.parse(inputStream);
        this.setWebAppConf(webXml.getChildNodeByName("web-app"));

        this.tomcatContext = tomcatContext;
    }

    @Override
    public void addWelcomePage(String welcomePage) {
        tomcatContext.addWelcomeFile(welcomePage);
    }

    @Override
    public void addListener(String listenerClass) {
        tomcatContext.addApplicationListener(listenerClass);
    }

    @Override
    public void addErrorPage(String location, Integer errorCode) {
        ErrorPage errorPage = new ErrorPage();
        errorPage.setErrorCode(errorCode);
        errorPage.setLocation(location);
        tomcatContext.addErrorPage(errorPage);
    }

    @Override
    public void addContextParam(String paramName, String paramValue) {
        ApplicationParameter parameter = new ApplicationParameter();
        parameter.setName(paramName);
        parameter.setValue(paramValue);

        tomcatContext.addParameter(paramName, paramValue); // ? addApplicationParameter
    }

    @Override
    public void addFilter(FilterConf filterConf) {
        String filterName = (String) filterConf.getFilterName();
        Class<? extends Filter> filterClass = (Class<? extends Filter>) filterConf.getFilterClass();

        FilterDef filterDef = new FilterDef();
        filterDef.setFilterName(filterName);
        filterDef.setFilterClass(filterClass.getName());
        Map<String, String> initParamMap = (Map<String, String>) filterConf.getInitParamMap();
        for (Entry<String, String> entry : initParamMap.entrySet()) {
            filterDef.addInitParameter(entry.getKey(), entry.getValue());
        }

        tomcatContext.addFilterDef(filterDef);
    }

    @Override
    public void addServlet(ServletConf servletConf) {
        String servletName = servletConf.getServletName();
        Class<? extends Servlet> servletClass = (Class<? extends Servlet>) servletConf.getServletClass();

        Wrapper servlet = tomcatContext.createWrapper();
        servlet.setName(servletName);
        servlet.setServletClass(servletClass.getName());

        Map<String, String> initParamMap = (Map<String, String>) servletConf.getInitParamMap();
        for (Entry<String, String> entry : initParamMap.entrySet()) {
            servlet.addInitParameter(entry.getKey(), entry.getValue());
        }

        Integer loadOnStartup = (Integer) servletConf.getLoadOnStartup();
        if (null != loadOnStartup) {
            servlet.setLoadOnStartup(loadOnStartup);
        }

        tomcatContext.addChild(servlet);

        String[] urlPatterns = servletConf.getUrlPattern();
        for (String urlPattern : urlPatterns) {
            this.addServletMapping(servletName, urlPattern);
        }
    }

    @SuppressWarnings("deprecation")
    private void addServletMapping(String servletName, String urlPattern) {
        tomcatContext.addServletMapping(urlPattern, servletName);
    }

    @Override
    public void addFilterUrlMapping(FilterMappingConf filterMappingConf) {
        FilterMap filterMap = new FilterMap();
        filterMap.setFilterName(filterMappingConf.getFilterName());
        for (String urlPattern : filterMappingConf.getUrlPatternList()) {
            filterMap.addURLPattern(urlPattern);
        }

        for (String servletName : filterMappingConf.getServletNameList()) {
            filterMap.addServletName(servletName);
        }

        for (String dispatcherType : filterMappingConf.getDispatcherTypeList()) {
            filterMap.setDispatcher(dispatcherType);
        }

        tomcatContext.addFilterMap(filterMap);
    }
}